package
{
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.net.*;
	import flash.geom.Point;
	
	/**
	 * clase qui resprente une Map.
	 * @author anthony & oussama
	 * */
	public class Map extends Sprite
	{
		// Constantes
		public static const MAX_LIGNES:uint = 31;
		public static const MAX_COLONNES:uint = 28;
		
		public static const PATH_PREFIX:String = "../map/";
		
		public var urlXml:String;
		public var nomNiveau:String;
		public var numNiveau:int;
		public var totalGommes:int;
		public var nbGommesRestant:uint;
		public var posFruit:Point;
		public var posDepartPacman:Point;
		
		public var pacman:Pacman;
		
		public var loaded:Boolean;
		
		// Tableau a 2 dimensions
		public var grilleCases:Array;
		
		/**
		 * Constructeur de Map
		 * @param	urlXml chemin du fichier XML
		 * @param	nomNiveau nom du niveau
		 * @param	numNiveau numero du niveau
		 */
		public function Map(urlXml:String, nomNiveau:String, numNiveau:int)
		{
			
			this.urlXml = PATH_PREFIX + urlXml;
			this.nomNiveau = nomNiveau;
			this.numNiveau = numNiveau;
			
			grilleCases = new Array();
			this.totalGommes = 0;
			this.nbGommesRestant = 0;
			
			this.loaded = false;
		
		}
		
		/**
		 * Charge le contenu du XML et construit la grille de cases.
		 */
		public function charger():void
		{
			var chargeur:URLLoader = new URLLoader();
			chargeur.dataFormat = URLLoaderDataFormat.TEXT;
			chargeur.addEventListener(Event.COMPLETE, construireMap);
			chargeur.load(new URLRequest(urlXml));
		}
		
		/**
		 * Construit la map à partir des données XML.
		 * Fonction appelée lorsque le chargement du fichier XML est fini
		 * @param	evt
		 */
		private function construireMap(evt:Event):void
		{
			try
			{
				var niveau:XML = new XML(evt.target.data);
				
				// Analyse du XML
				
				// Position de départ de Pacman
				var xPacman:int = int(niveau.pacman.@col);
				var yPacman:int = int(niveau.pacman.@ligne);
				posDepartPacman = new Point(xPacman, yPacman);
				pacman = new Pacman(posDepartPacman, false, Direction.WEST);
				//trace("pos Pacman: " + posDepartPacman);
				
				// Position du fruit bonus
				var xFruit:int = int(niveau.fruit.@col);
				var yFruit:int = int(niveau.fruit.@ligne);
				posFruit = new Point(xFruit, yFruit);
				//trace("pos Fruit: " + posFruit);
				
				// Lecture des lignes
				var listeLignes:XMLList = niveau.map.ligne;
				var numLigne:uint = 0;
				for each (var ligne:XML in listeLignes)
				{
					traiterLigne(ligne, numLigne);
					numLigne++;
				}
				
				// DEBUG
				//trace("nbLignes = " + grilleCases.length);
				//trace("nbColonnes = " + grilleCases[0].length);
				
				dessinerMap();
				
				// Analyse terminée : map chargée
				loaded = true;
			}
			catch (err:TypeError)
			{
				trace("Erreur chargement XML\n" + err.message);
			}
		} // construireMap
		
		/**
		 * Traite le contenu d'une balise ligne, et construit les cases
		 * correspondantes
		 * @param	ligne
		 */
		private function traiterLigne(ligne:XML, numLigne:uint):Boolean
		{
			var chaine:String = ligne.toString();
			
			// DEBUG
			//trace(chaine + " = " + chaine.length);
			
			// Liste des cases ( = 1 ligne de la grille)
			var listeCases:Array = new Array();
			
			// Case courante
			var typeCase:uint;
			var c:Case;
			
			// Lecture caractère par caractère : 1 caractère = 1 case
			for (var numCol:int = 0; numCol < chaine.length; numCol++)
			{
				typeCase = int(chaine.charAt(numCol));
				
				switch (typeCase)
				{
					case Case.CASE_MUR:
						c = new CasePleine(numLigne, numCol);
						break
					
					case Case.CASE_SORTIE:
						c = new CaseSortie(numLigne, numCol);
						break;
					
					case Case.CASE_VIDE:
					case Case.CASE_GOMME:
					case Case.CASE_SUPER_GOMME:
					default:
						this.totalGommes++;
						this.nbGommesRestant++;
						c = new CaseVide(typeCase, numLigne, numCol);
						break;
				}
				
				// DEBUG
				//trace(cCourante.toString());
				
				// On ajoute la case courante
				listeCases[numCol] = c;
			}
			
			// On ajoute la ligne de Cases à la grille
			grilleCases[numLigne] = listeCases;
			
			return true; // XXX compléter suivant succès/echec lecture ligne
		
		} // traiterLigne
		
		/**
		 * Dessine la map
		 */
		private function dessinerMap():void
		{
			// Cases
			var ligne:uint;
			var col:uint;
			var c:Case;
			for (ligne = 0; ligne < grilleCases.length; ligne++)
			{
				for (col = 0; col < grilleCases[ligne].length; col++)
				{
					c = grilleCases[ligne][col] as Case;
					c.x = col * Case.LARGEUR;
					c.y = ligne * Case.HAUTEUR;
					
					if (c.typeCase == Case.CASE_MUR)
						calculerTypeMur(c as CasePleine);
					
					this.addChild(c);
				}
			}
			
			// Pacman
			pacman.x = pacman.posCourante.x * Case.LARGEUR - Pacman.LARGEUR / 2;
			pacman.y = pacman.posCourante.y * Case.HAUTEUR - Pacman.HAUTEUR / 2;
			this.addChild(pacman);
		}
		
		/**
		 * Détermine le type de mur d'une case en fonction de ses voisines.
		 * @param	c
		 */
		private function calculerTypeMur(c:CasePleine):void
		{
			c.setTypeMur(CasePleine.MUR_BLOC);
		
			// A DEBUGGER
		/*
		   var cNord:Case = getVoisin(c, Direction.NORD);
		   var cSud:Case = getVoisin(c, Direction.SUD);
		   var cEast:Case = getVoisin(c, Direction.EAST);
		   var cWest:Case = getVoisin(c, Direction.WEST);
		
		   // coin sup gauche
		   if ((cEast != null && cEast.typeCase == Case.CASE_MUR) && (cSud != null && cSud.typeCase == Case.CASE_MUR))
		   c.setTypeMur(CasePleine.MUR_COIN_SUP_GAUCHE);
		   // coin sup droit
		   else if ((cWest != null && cWest.typeCase == Case.CASE_MUR) && (cSud != null && cSud.typeCase == Case.CASE_MUR))
		   c.setTypeMur(CasePleine.MUR_COIN_SUP_DROIT);
		   // coin inf gauche
		   else if ((cEast != null && cEast.typeCase == Case.CASE_MUR) && (cNord != null && cNord.typeCase == Case.CASE_MUR))
		   c.setTypeMur(CasePleine.MUR_COIN_INF_GAUCHE);
		   // coin inf droit
		   else if ((cWest != null && cWest.typeCase == Case.CASE_MUR) && (cNord != null && cNord.typeCase == Case.CASE_MUR))
		   c.setTypeMur(CasePleine.MUR_COIN_INF_DROIT);
		   // vertical
		   else if ((cSud != null && cSud.typeCase == Case.CASE_MUR) && (cNord != null && cNord.typeCase == Case.CASE_MUR))
		   c.setTypeMur(CasePleine.MUR_VERTICAL);
		   // horizontal
		   else if ((cWest != null && cWest.typeCase == Case.CASE_MUR) && (cEast != null && cEast.typeCase == Case.CASE_MUR))
		   c.setTypeMur(CasePleine.MUR_HORIZONTAL);
		   else
		   c.setTypeMur(CasePleine.MUR_BLOC);
		 */
		}
		
		/**
		 * Retourne la case voisine de C se trouvant à la direction donnée.
		 * @param	c La case dont on veut avoir le voisin.
		 * @param	dir La direction.
		 * @return La case voisine.
		 */
		public function getVoisin(c:Case, dir:Direction):Case
		{
			if (c == null || dir == null)
				return null;
			
			if (dir == Direction.NORD)
			{
				if (c.ligne == 0)
					return null;
				else
					return grilleCases[c.ligne - 1][c.col];
			}
			else if (dir == Direction.SUD)
			{
				if (c.ligne == MAX_LIGNES - 1)
					return null;
				else
					return grilleCases[c.ligne + 1][c.col];
			}
			else if (dir == Direction.EAST)
			{
				if (c.col == MAX_COLONNES - 1)
					return null;
				else
					return grilleCases[c.ligne][c.col + 1];
			}
			else if (dir == Direction.WEST)
			{
				if (c.col == 0)
					return null;
				else
					return grilleCases[c.ligne][c.col - 1];
			}
			
			return null;
		}
	}

}